package com.aura.common.redis.config;

import com.aura.common.domain.constants.CommonConstants;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * Redis 配置类：统一配置 RedisTemplate 的 key、value 序列化方式，避免乱码、类型错误等问题。
 */
@Configuration
public class RedisConfig {

    /**
     * RedisTemplate 配置
     * 核心作用：用于定义 redis 的 key/value 和 hashKey/hashValue 的序列化方式
     *
     * @param redisConnectionFactory Spring Boot 自动注入的 Redis 连接工厂
     * @return 配置好的 RedisTemplate
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();

        // 设置 Redis 连接工厂
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        // 🔑 设置 key 和 hashKey 的序列化方式：使用 String 序列化，避免乱码
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());

        // 🔐 设置 value 和 hashValue 的序列化方式：使用自定义 Jackson 序列化器，支持对象转 JSON
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = createJacksonSerializer();
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        // 完成属性设置
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 创建 Redis 用的 Jackson 序列化器（GenericJackson2JsonRedisSerializer）
     * 配置说明：
     * - 支持 Java 8 日期类型（如 LocalDateTime）
     * - 日期格式统一为 yyyy-MM-dd HH:mm:ss
     * - 忽略未知字段、空对象等反序列化异常
     *
     * @return Jackson 序列化器
     */
    private GenericJackson2JsonRedisSerializer createJacksonSerializer() {
        ObjectMapper OBJECT_MAPPER = JsonMapper.builder()
                //  忽略未知字段（防止 POJO 变更后反序列化报错）
                .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                //  日期不要序列化成时间戳
                .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
                //  忽略空对象异常
                .configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false)
                //  忽略反序列化失败的子类型
                .configure(DeserializationFeature.FAIL_ON_INVALID_SUBTYPE, false)
                //  禁用写入 key 为时间戳（用于 Map 的 key）
                .configure(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS, false)
                //  禁用注解（Jackson 默认支持注解，这里视项目而定）
                .configure(MapperFeature.USE_ANNOTATIONS, false)
                //  支持 Java 8 时间模块（LocalDateTime）
                .addModule(new JavaTimeModule())
                //  自定义 LocalDateTime 序列化、反序列化格式
                .addModule(new SimpleModule()
                        .addSerializer(LocalDateTime.class,
                                new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(CommonConstants.STANDARD_FORMAT)))
                        .addDeserializer(LocalDateTime.class,
                                new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(CommonConstants.STANDARD_FORMAT)))
                )
                //  全局默认日期格式（兜底策略）
                .defaultDateFormat(new SimpleDateFormat(CommonConstants.STANDARD_FORMAT))
                //  序列化时排除 null 字段，减少冗余
                .serializationInclusion(JsonInclude.Include.NON_NULL)
                .build();

        // 返回 Redis 序列化器（内置类型信息，兼容反序列化）
        return new GenericJackson2JsonRedisSerializer(OBJECT_MAPPER);
    }
}
